package edu.bu.cs511.p5;

import java.util.ListIterator;

/**
 * FPScheduler A Fixed Priority scheduler.
 * <p/>
 *
 * This is the implementation of the Fixed priority scheduler that can
 * be used to implement such polices as round robin given proper
 * schedulability tests.  Each task has a priority associated with it
 * (0 by default), and the scheduler will always execute those tasks
 * with the highest priority.  If multiple tasks have the same
 * priority, then the tasks go in round-robin order.<p/>
 *
 * For RI and AF, see GenericScheduler.
 * 
 * <p/>
 * Can remove the synchonized from the methods and attach it to datastructures
 * if there are scalability issues.
 * <p/>
 * 4/9/06, Gabriel Parmer: migrated from RRScheduler
 * <p/> 
 * 4/10/06, Gabriel Parmer: generalized and extended GenericScheduler
 */
public class FPScheduler extends GenericScheduler {
    /*
     * For RI and AF, see GenericScheduler.java
     */

    /*
     * This will be inserted into every Task scheduled by this scheduler and
     * includes the priority data needed to make scheduling decisions.
     */
    private class FPData extends SchedData {
        public int priority;

        /**
         * @REQUIRES prior is the priority of the task.
         * <p/>
         * @MODIFIES sets the priority to the argument value.
         */
        public FPData(int prior) {
            super();
            priority = prior;
        }

        /** @MODIFIES sets the priority of the task to 0. */
        public FPData() {
            this(0);
        }

        /** @EFFECTS return the current allocated Concurrency */
        public int getPriority() {
            return priority;
        }
    }

    /**
     * Default constructor to create a FPScheduler.
     * <p/>
     * @REQUIRES none
     */
    public FPScheduler() {
        super();
    }

    /**
     * Constructor whereby one can specify the maximum desired
     * allowable concurrency.
     * 
     * <p/>
     * @REQUIRES maxConcurr is the maximum value for the concurrency
     * supported by this scheduler, or the maximum number of threads
     * it will pass to children.
     */
    public FPScheduler(int maxConcurr) {
        super(maxConcurr);
    }

    /**
     * Insert a given task into the runqueue for this scheduler.  This
     * logic exists for the FPScheduler as we need to insert into the
     * runqueue at a place appropriate for our priority as the
     * runqueue is sorted.<p/>
     * 
     * @REQUIRES t is the task to be insert into the runQueue.
     * <p/>
     * @MODIFIES runQueue is modified in that t is added to it in a manner that
     * respects priorities.
     */
    protected void insertRunQueue(Task t) {
        ListIterator<Task> li = runQueue.listIterator(0);
        boolean insertAtEnd = true;

        //System.out.print("\ninsert "+ ((FPData)t.schedData).getPriority()+" into runqueue: ");
        while (li.hasNext()) {
            Task cur = li.next();

            //System.out.print(((FPData)cur.schedData).getPriority() +", ");

            if (((FPData) cur.schedData).getPriority() <
                    ((FPData) t.schedData).getPriority()) {
                insertAtEnd = false;
                break;
            }
        }

        if (insertAtEnd) {
            li.add(t);
            //System.out.println("Adding task to end of runQueue.");
        } else {
            li.previous();
            li.add(t);
            //System.out.println("Adding task into the queue in the middle.");
        }
    }

    /**
     * Add a new task to this scheduler's structures.  Specify a
     * priority that task is to have.<p/>
     *
     * @REQUIRES t is the task to add, and s must be an integer
     * specifying the priority of that task.  If a string is passed
     * that cannot be formatted to be an integer, priority will
     * default to 0.
     * 
     * <p/>
     * @MODIFIES adds the task to the waitingList of this scheduler and sets its
     * priority to be an integer designated by the String s.
     *
     * @EFFECTS returns true.
     */
    synchronized public boolean addTask(Task t, String s) {
        int priority;

        /* Not on a fast path, so this should be acceptable. */
        try {
            priority = Integer.parseInt(s);
        } catch (NumberFormatException nfe) {
            priority = 0;
        }

        //System.out.println("Adding Task with priority "+priority);

        t.schedData = new FPData(priority);

        waitingList.add(t);

        return true;
    }

    /**
     * Add the task to the waiting list of this scheduler without
     * explicitly setting its priority.  Priority is defaulted to
     * 0.<p/>
     * 
     * @MODIFIES add the task t to the waitingList of this scheduler.
     * <p/>
     * @REQUIRES t is a Task that is not a ThreadManager
     * <p/>
     * @EFFECTS returns true.
     */
    synchronized public boolean addTask(Task t) {
        addTask(t, "");

        return true;
    }
}
